package JUC.old;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

public class CAS和ABA问题 {
    public static void main(String[] args) {
        compareAndSet_CAS_Demo();
    }

    private static void AtomicStampedReference_ABA() {
        AtomicReference<Integer> A=new AtomicReference<>(1); //原子引用
        AtomicStampedReference<Integer> a=new AtomicStampedReference<>(1,1);
        System.out.println("=============以下是ABA问题的产生=========");

        new Thread(()->{
            A.compareAndSet(1,2);
            A.compareAndSet(2,1);
        },"t1").start();
        new Thread(()->{
            try{
                TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e){e.printStackTrace();}
            System.out.println(A.compareAndSet(1, 11)+"\t"+A.get());
        },"t2").start();
        try{TimeUnit.SECONDS.sleep(2);}catch (InterruptedException e){e.printStackTrace();}

        System.out.println("=============以下是ABA问题的解决=========");

        new Thread(()->{
            int stamp = a.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t第一次版本号"+stamp+"\t第一次的值"+a.getReference());
            try{TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e){e.printStackTrace();}

            a.compareAndSet(1,2,a.getStamp(),a.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t第二次版本号"+a.getStamp()+"\t第二次的值"+a.getReference());
            a.compareAndSet(2,1,a.getStamp(),a.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t第三次版本号"+a.getStamp()+"\t第三次的值"+a.getReference());
        },"t3").start();
        new Thread(()->{
            int stamp = a.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t第一次版本号"+stamp+"\t第一次的值"+a.getReference());
            try{TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}
            boolean k=a.compareAndSet(1,3,stamp,stamp+1);
            System.out.println(Thread.currentThread().getName()+"\t修改"+k+"当前版本号"+a.getStamp()+"\t当前值"+a.getReference());
            System.out.println(Thread.currentThread().getName()+"当前值"+a.getReference());
        },"t4").start();
    }

    private static void compareAndSet_CAS_Demo() {
        AtomicReference<Integer> userAtomicReference=new AtomicReference<>(); //原子引用
        /**
         *   compareAndSet（CAS）比较并交换   用的是Unsafe原语 不可被打断
         *                                  当前对象    内存偏移量    添加的值
         *   public final int getAndAddInt(Object o, long offset, int delta) {
         *         int v;
         *         do {
         *             v = getIntVolatile(o, offset);
         *         } while (!weakCompareAndSetInt(o, offset, v, v + delta));
         *         return v;
         *     }
         *
         *     用do{}while();自旋锁
         *     CAS缺点:
         *         如果CAS一直不成功  循环时间长  会让cpu开销大
         *         只能保证一个变量
         *         会引发ABA问题:
         *
         *
         */
        AtomicInteger atomicInteger=new AtomicInteger(5);
        atomicInteger.compareAndSet(5,6);//凭啥能不加锁实现原子性   它使用unsafe（系统原语  不可能被打断） 也用到了CAS
        atomicInteger.compareAndSet(6,5);//凭啥能不加锁实现原子性   它使用unsafe（系统原语  不可能被打断） 也用到了CAS
        System.out.println(atomicInteger.compareAndSet(5, 55)+"变成"+atomicInteger);//比较  如果比较相等就交换
    }
}
